package com.service.abolishing.service.impl;

import com.service.abolishing.dao.LocationResultDao;
import com.service.abolishing.dao.UserInfoDao;
import com.service.abolishing.dto.WeightTrilateral;
import com.service.abolishing.entity.LocationResult;
import com.service.abolishing.entity.TerminalList;
import com.service.abolishing.entity.UserInfo;
import com.service.abolishing.service.LocationResultService;
import com.service.config.utils.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.awt.geom.Point2D;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 定位结果表(LocationResult)表服务实现类
 *
 * @author makejava
 * @since 2021-10-21 14:14:36
 */
@Service("locationResultService")
@Slf4j
public class LocationResultServiceImpl implements LocationResultService {
    @Resource
    private LocationResultDao locationResultDao;
    @Resource
    WeightTrilateral weightTrilateral;
    @Resource
    private RedisUtil redisUtil;
    @Resource
    private UserInfoDao userInfoDao;
    /**
     * 通过ID查询单条数据
     *
     * @param id 主键
     * @return 实例对象
     */
    @Override
    public LocationResult queryById(String id) {
        return this.locationResultDao.queryById(id);
    }

    /**
     * 查询多条数据
     *
     * @param offset 查询起始位置
     * @param limit  查询条数
     * @return 对象列表
     */
    @Override
    public List<LocationResult> queryAllByLimit(int offset, int limit) {
        return this.locationResultDao.queryAllByLimit(offset, limit);
    }

    /**
     * 新增数据
     *
     * @param locationResult 实例对象
     * @return 实例对象
     */
    @Override
    public LocationResult insert(LocationResult locationResult) {
        this.locationResultDao.insert(locationResult);
        return locationResult;
    }

    /**
     * 修改数据
     *
     * @param locationResult 实例对象
     * @return 实例对象
     */
    @Override
    public LocationResult update(LocationResult locationResult) {
        this.locationResultDao.update(locationResult);
        return this.queryById(locationResult.getId());
    }

    /**
     * 通过主键删除数据
     *
     * @param id 主键
     * @return 是否成功
     */
    @Override
    public boolean deleteById(String id) {
        return this.locationResultDao.deleteById(id) > 0;
    }

    @Override
    public void getLocationResult(List<TerminalList> terminalListUpdate,String manage_id) {
        List<LocationResult> locationResultList = new ArrayList<>();
        Map<String, List<TerminalList>> collect = terminalListUpdate.stream().collect(Collectors.groupingBy(TerminalList::getTerminalmac));
        log.info("collect--start");
        //内部遍历 比较
        collect.forEach((key, value) -> {
            String terminalMac = key;
            key = key.replaceAll(":","").concat(":info");
            String id = "";
            int rssi = 0;
            try {
                StringBuilder str = new StringBuilder();
                getString(str,value,id,rssi);
                str.append(key);
                LocationResult locationresult = weightTrilateral.getLocation(str.toString());
                if (locationresult != null) {
                    if (!locationresult.getTerminalX().isNaN() && !locationresult.getTerminalY().isNaN()) {
                        locationresult.setTerminalMac(terminalMac);
                        locationresult.setProbability(50);
                        locationresult.setStatus(1);
                        locationresult.setUpdateTime(new Date());
                        locationresult.setId(IdUtil.getStringId());
                        locationresult.setManageInfoId(manage_id);
                        Map<String, List<Point2D.Double>> stringListMap = filterAndAnalysis(terminalMac, 1);
                        boolean analysis = analysis(terminalMac, stringListMap, locationresult);
                        if (!analysis) {
                            locationresult.setProbability(100);
                            locationresult.setStatus(2);
                        }else {
                            judgeArea(stringListMap, locationresult, 2);// 出海区域
                        }
                    }
                }if (locationresult != null) {
                    if (redisUtil.exist(key)) {
                        List<LocationResult> locationResultList1 = new ArrayList<>();
                        long l = redisUtil.selectListSize(key);
                        if (l >= 2) {
                            List list = redisUtil.getList(key);
                            for (Object o : list) {
                                LocationResult locationResult = JsonXMLUtils.json2obj(o.toString(), LocationResult.class);
                                locationResultList1.add(locationResult);
                            }
                            redisUtil.delete(key);
                            locationResultList1.add(locationresult);
                            LocationResult data = getData(locationResultList1);
                            if (data != null && data.getFlag() == null) {
                                locationResultList.add(data);
                            }
                        }else {
                            redisUtil.leftPush(key, JsonXMLUtils.obj2json(locationresult));
                        }
                    }else {
                        locationresult.setFlag(true);
                        redisUtil.leftPush(key, JsonXMLUtils.obj2json(locationresult));
                        locationResultList.add(locationresult);
                    }
                }

            }catch (Exception e) {
                e.printStackTrace();
            }
        });
        if (locationResultList.size() > 0){
            List<UserInfo> userInfoList = new ArrayList<>();
            locationResultList.forEach(locationResult -> {
                UserInfo userInfo = new UserInfo();
                userInfo.setUMac(locationResult.getTerminalMac());
                userInfo.setProbability(locationResult.getProbability());
                userInfo.setStatus(locationResult.getStatus());
                userInfo.setUpdateTime(locationResult.getUpdateTime());
                locationResult.setTimestamp(new Date());
                if (userInfo.getStatus() == 0) {
                    userInfo.setLeaveTime(new Date());
                }
                if (userInfo.getStatus() == 1) {
                    userInfo.setLoginTime(new Date());
                }
                if (userInfo.getProbability() > 50) {
                    userInfoList.add(userInfo);
                }
            });

            locationResultDao.insertBatch(locationResultList);
            if (userInfoList.size() > 0) {
                userInfoDao.insertOrUpdateBatchByMac(userInfoList);
            }
            log.info("完成定位");
        }
    }

    private LocationResult getData(List<LocationResult> locationResultList1) {
        List<LocationResult> collect = locationResultList1.stream().sorted(Comparator.comparing(LocationResult::getProbability).reversed()).collect(Collectors.toList());
        boolean present = collect.stream().findFirst().isPresent();
        if (present) {
            LocationResult locationResult = collect.stream().findFirst().get();
            if (locationResult.getProbability() > 50) {
                return locationResult;
            }
        }
        return null;
    }

    /**
     *
     * @param stringListMap
     * @param locationresult
     * @param type
     * @throws Exception
     */
    private LocationResult judgeArea(Map<String, List<Point2D.Double>> stringListMap,LocationResult locationresult,int type ) throws Exception {
        stringListMap = filterAndAnalysis(locationresult.getTerminalMac(), type);
        boolean analysis = analysis(locationresult.getTerminalMac(), stringListMap, locationresult); // 分析所属区域
        if (analysis) {
            if (type == 2) {
                locationresult.setStatus(0); // 出海
                locationresult.setProbability(UuIDUtil.randomNum(70,90)); //概率
            }
            if (type == 3) {
                Random random = new Random();
                int i = random.nextInt(2);
                locationresult.setStatus(i); // 出海或者在岸
                locationresult.setProbability(UuIDUtil.randomNum(40,70)); //概率
            }
            if (type == 4) {
                locationresult.setStatus(1); // 出海或者在岸
                locationresult.setProbability(UuIDUtil.randomNum(40,70)); //概率
            }
        }else {
            type++;
            judgeArea(stringListMap, locationresult, type);
        }
        return locationresult;
    }

    private boolean analysis(String key, Map<String, List<Point2D.Double>> stringListMap, LocationResult locationresult) {
        Double terminalY = locationresult.getTerminalY();
        Double terminalX = locationresult.getTerminalX();
        if (stringListMap != null) {
            List<Point2D.Double> doubles = stringListMap.get(key);
            Point2D.Double aDouble = new Point2D.Double(terminalX, terminalY);
            boolean ptInPoly = GeometryUtil.isPtInPoly(aDouble, doubles); // 计算是否在区域内
            if (ptInPoly) { //是否在全区域内
                return true;
            }else {
                return false;
            }
        }
        return false;
    }

    private void getString(StringBuilder str, List<TerminalList> value, String id, int rssi) {
        for (TerminalList terminalList : value) {
            id = terminalList.getApmac();
            rssi = terminalList.getMacrssi();
            str.append(id).append(",").append(rssi).append(";");
        }
    }

    @Override
    public List<LocationResult> queryByTerminalMac(String terminalmac, String startDate, String endDate) {
        if (startDate !=null && ! startDate.equals("")  && endDate !=null && !endDate.equals("")){
            return queryByCondition (terminalmac,startDate,endDate);
        }else {
            return locationResultDao.queryAll(new LocationResult());
        }
    }

    @Override
    public List<LocationResult> getLocationResultByMac(String terminalMac) {
        return locationResultDao.getLocationResultByMac(terminalMac);
    }

    @Override
    public List<LocationResult> getHistoryLocation(String startDate, String endDate) {
        return locationResultDao.getHistoryLocation(startDate,endDate);
    }

    /**
     * 筛选条件
     * @param terminalMac
     * @param startDate
     * @param endDate
     * @return
     */
    private List<LocationResult> queryByCondition(String terminalMac, String startDate, String endDate) {
        Date startDate1= DateUtil.date(startDate);
        startDate = DateUtil.datetoString(startDate1);
        endDate = DateUtil.datetoString(DateUtil.dateFour(endDate));
        if (terminalMac != null && !terminalMac.equals("")){
            return locationResultDao.queryByCondition(terminalMac,startDate,endDate);
        }else {
            return locationResultDao.queryBytTwoDate(startDate,endDate);
        }
    }
    /**
     * 分解渔港的坐标信息
     */
    private Map<String, List<Point2D.Double>> filterAndAnalysis(String  id, int  type) throws Exception {
        String buildingsInfoList = null;
        if (type == 1) {
            buildingsInfoList = "(0.0,0.0)-(13.32,0)-(13.32,8.62)-(0,8.62)";// 整个渔港
        }
        if (type == 2) {
            buildingsInfoList = "(13.3,3.53)-(8.98,3.85)-(6.41,3.79)-(4.33,7.72)";// 出海区域
        }
        if (type == 3) {
            buildingsInfoList = "(0.6,4.74)-(3.7,1.17)-(8.99,1.23)-(6.41,3.79)-(4.33,7.72)";// 出海或在岸
        }
        if (type == 4) {
            buildingsInfoList = "(3.6,8.24)-(0.05,4.84)-(0.24,0.52)-(9,0.38)-(8.99,1.23)-(3.7,1.17)-(0.6,4.74)-(4.33,7.72)";// 在岸区域
        }
        if (buildingsInfoList == null) {
            return null;
        }
        //将所有的坐标画成图
        Map<String, List<Point2D.Double>> categoryMap = new HashMap<>();
        List<Point2D.Double> points = new ArrayList<>();
        String[] split = buildingsInfoList.replaceAll("\\(", "").replaceAll("\\)", "").split("-");
        for (int i = 0; i < split.length; i++) {
            String[] split1 = split[i].split(",");
            String x = split1[0];
            String y = split1[1];
            points.add(new Point2D.Double(Double.parseDouble(x), Double.parseDouble(y)));
        }
        categoryMap.put(id, points);
        return categoryMap;
    }
}
